Micron Document
🎖️GitЯра🎖️

Node / meshtastic / Meshtastic-Android / files / core / model / src / commonTest / kotlin / org / meshtastic / core / model / util / MeshBeaconOfferTest.kt

Displaying Raw • Download

core/model/src/commonTest/kotlin/org/meshtastic/core/model/util/MeshBeaconOfferTest.kt b4bedd92fcc8d65daff79200d71f6ebc3d8f0cfa (b4bedd92) Text, 9.67 KB

T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.model.util

Tff7b72import T7ee787okio.ByteString.Companion.encodeUtf8
Tff7b72import T7ee787org.meshtastic.core.model.MeshBeaconOffer
Tff7b72import T7ee787org.meshtastic.proto.ChannelSettings
Tff7b72import T7ee787org.meshtastic.proto.Config.LoRaConfig
Tff7b72import T7ee787org.meshtastic.proto.Config.LoRaConfig.ModemPreset
Tff7b72import T7ee787org.meshtastic.proto.Config.LoRaConfig.RegionCode
Tff7b72import T7ee787org.meshtastic.proto.MeshBeacon
Tff7b72import T7ee787kotlin.test.Test
Tff7b72import T7ee787kotlin.test.assertEquals
Tff7b72import T7ee787kotlin.test.assertNotNull
Tff7b72import T7ee787kotlin.test.assertNull

Tff7b72class T56d364MeshBeaconOfferTest Tb4b4b4{

Tff7b72private Tff7b72val Te6edf3radioLora Tff7b72=
Te6edf3LoRaConfigTb4b4b4(Te6edf3use_preset Tff7b72= Tff7b72trueTb4b4b4, Te6edf3modem_preset Tff7b72= Te6edf3ModemPresetTb4b4b4.Te6edf3LONG_FASTTb4b4b4, Te6edf3region Tff7b72= Te6edf3RegionCodeTb4b4b4.Te6edf3USTb4b4b4, Te6edf3channel_num Tff7b72= T79c0ff0Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3radioChannels Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffHomeMeshTa5d6ff"Tb4b4b4)Tb4b4b4)

Tf0883e@Test
Tff7b72fun Td2a8ff`no offer channel yields NONE`Tb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3beacon Tff7b72= Te6edf3MeshBeaconTb4b4b4(Te6edf3message Tff7b72= Ta5d6ff"Ta5d6ffhiTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3BeaconJoinOptionTb4b4b4.Te6edf3NONETb4b4b4, Te6edf3beaconTb4b4b4.Te6edf3beaconJoinOptionTb4b4b4(Te6edf3radioLoraTb4b4b4, Te6edf3radioChannelsTb4b4b4)Tb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`matching preset region and slot yields ADD`Tb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// Offering the radio's own primary channel name forces an identical name-hash slot → addable with no reboot.
Tff7b72val Te6edf3beacon Tff7b72=
Te6edf3MeshBeaconTb4b4b4(
Te6edf3offer_channel Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffHomeMeshTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3offer_preset Tff7b72= Te6edf3ModemPresetTb4b4b4.Te6edf3LONG_FASTTb4b4b4,
Te6edf3offer_region Tff7b72= Te6edf3RegionCodeTb4b4b4.Te6edf3USTb4b4b4,
Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3BeaconJoinOptionTb4b4b4.Te6edf3ADDTb4b4b4, Te6edf3beaconTb4b4b4.Te6edf3beaconJoinOptionTb4b4b4(Te6edf3radioLoraTb4b4b4, Te6edf3radioChannelsTb4b4b4)Tb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`unnamed primary matches a beacon that names the preset explicitly yielding ADD`Tb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// The radio's primary has an empty name (resolves to the preset display name "LongFast" for the slot hash); a
T8b949e// beacon offering a channel literally named "LongFast" on the same preset+region is the same slot -> ADD.
T8b949e// Without effective-name resolution the empty primary would hash "" and misclassify as SWITCH.
Tff7b72val Te6edf3emptyPrimary Tff7b72= Te6edf3listOfTb4b4b4(Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3beacon Tff7b72=
Te6edf3MeshBeaconTb4b4b4(
Te6edf3offer_channel Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffLongFastTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3offer_preset Tff7b72= Te6edf3ModemPresetTb4b4b4.Te6edf3LONG_FASTTb4b4b4,
Te6edf3offer_region Tff7b72= Te6edf3RegionCodeTb4b4b4.Te6edf3USTb4b4b4,
Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3BeaconJoinOptionTb4b4b4.Te6edf3ADDTb4b4b4, Te6edf3beaconTb4b4b4.Te6edf3beaconJoinOptionTb4b4b4(Te6edf3radioLoraTb4b4b4, Te6edf3emptyPrimaryTb4b4b4)Tb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`different preset forces SWITCH`Tb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3beacon Tff7b72=
Te6edf3MeshBeaconTb4b4b4(
Te6edf3offer_channel Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffHomeMeshTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3offer_preset Tff7b72= Te6edf3ModemPresetTb4b4b4.Te6edf3SHORT_FASTTb4b4b4,
Te6edf3offer_region Tff7b72= Te6edf3RegionCodeTb4b4b4.Te6edf3USTb4b4b4,
Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3BeaconJoinOptionTb4b4b4.Te6edf3SWITCHTb4b4b4, Te6edf3beaconTb4b4b4.Te6edf3beaconJoinOptionTb4b4b4(Te6edf3radioLoraTb4b4b4, Te6edf3radioChannelsTb4b4b4)Tb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`different region forces SWITCH`Tb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3beacon Tff7b72=
Te6edf3MeshBeaconTb4b4b4(
Te6edf3offer_channel Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffHomeMeshTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3offer_preset Tff7b72= Te6edf3ModemPresetTb4b4b4.Te6edf3LONG_FASTTb4b4b4,
Te6edf3offer_region Tff7b72= Te6edf3RegionCodeTb4b4b4.Te6edf3EU_868Tb4b4b4,
Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3BeaconJoinOptionTb4b4b4.Te6edf3SWITCHTb4b4b4, Te6edf3beaconTb4b4b4.Te6edf3beaconJoinOptionTb4b4b4(Te6edf3radioLoraTb4b4b4, Te6edf3radioChannelsTb4b4b4)Tb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`null lora config forces SWITCH`Tb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3beacon Tff7b72= Te6edf3MeshBeaconTb4b4b4(Te6edf3offer_channel Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffHomeMeshTa5d6ff"Tb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(
Te6edf3BeaconJoinOptionTb4b4b4.Te6edf3SWITCHTb4b4b4,
Te6edf3beaconTb4b4b4.Te6edf3beaconJoinOptionTb4b4b4(Te6edf3currentLora Tff7b72= Tff7b72nullTb4b4b4, Te6edf3currentChannels Tff7b72= Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`toJoinChannelSet omits lora for ADD and includes it for SWITCH`Tb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3beacon Tff7b72=
Te6edf3MeshBeaconTb4b4b4(
Te6edf3offer_channel Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffPartyNetTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3offer_preset Tff7b72= Te6edf3ModemPresetTb4b4b4.Te6edf3LONG_FASTTb4b4b4,
Te6edf3offer_region Tff7b72= Te6edf3RegionCodeTb4b4b4.Te6edf3USTb4b4b4,
Tb4b4b4)
Te6edf3assertNullTb4b4b4(Te6edf3beaconTb4b4b4.Te6edf3toJoinChannelSetTb4b4b4(Te6edf3BeaconJoinOptionTb4b4b4.Te6edf3ADDTb4b4b4, Te6edf3radioLoraTb4b4b4)Tff7b72?.Te6edf3lora_configTb4b4b4, Ta5d6ff"Ta5d6ffADD must not retuneTa5d6ff"Tb4b4b4)
Te6edf3assertNotNullTb4b4b4(Te6edf3beaconTb4b4b4.Te6edf3toJoinChannelSetTb4b4b4(Te6edf3BeaconJoinOptionTb4b4b4.Te6edf3SWITCHTb4b4b4, Te6edf3radioLoraTb4b4b4)Tff7b72?.Te6edf3lora_configTb4b4b4, Ta5d6ff"Ta5d6ffSWITCH carries loraTa5d6ff"Tb4b4b4)
Te6edf3assertNullTb4b4b4(Te6edf3beaconTb4b4b4.Te6edf3toJoinChannelSetTb4b4b4(Te6edf3BeaconJoinOptionTb4b4b4.Te6edf3NONETb4b4b4, Te6edf3radioLoraTb4b4b4)Tb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`SWITCH ships a fresh lora config so stale RF pins never survive the retune`Tb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// The join must NOT copy the current config: a stale channel_num / override / manual preset would strand the
T8b949e// radio on the old slot. use_preset is set, the offered preset+region applied, and every RF field left blank.
Tff7b72val Te6edf3current Tff7b72=
Te6edf3radioLoraTb4b4b4.Te6edf3copyTb4b4b4(
Te6edf3modem_preset Tff7b72= Te6edf3ModemPresetTb4b4b4.Te6edf3MEDIUM_FASTTb4b4b4,
Te6edf3region Tff7b72= Te6edf3RegionCodeTb4b4b4.Te6edf3EU_868Tb4b4b4,
Te6edf3hop_limit Tff7b72= T79c0ff7Tb4b4b4,
Te6edf3tx_power Tff7b72= T79c0ff2T79c0ff7Tb4b4b4,
Te6edf3tx_enabled Tff7b72= Tff7b72trueTb4b4b4,
Te6edf3channel_num Tff7b72= T79c0ff5Tb4b4b4,
Te6edf3override_frequency Tff7b72= T79c0ff9T79c0ff1T79c0ff5.5fTb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3beacon Tff7b72=
Te6edf3MeshBeaconTb4b4b4(
Te6edf3offer_channel Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffPartyNetTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3offer_preset Tff7b72= Te6edf3ModemPresetTb4b4b4.Te6edf3LONG_FASTTb4b4b4,
Te6edf3offer_region Tff7b72= Te6edf3RegionCodeTb4b4b4.Te6edf3USTb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3lora Tff7b72= Te6edf3beaconTb4b4b4.Te6edf3toJoinChannelSetTb4b4b4(Te6edf3BeaconJoinOptionTb4b4b4.Te6edf3SWITCHTb4b4b4, Te6edf3currentTb4b4b4)Tff7b72?.Te6edf3lora_config
Te6edf3assertNotNullTb4b4b4(Te6edf3loraTb4b4b4)
Te6edf3assertEqualsTb4b4b4(Tff7b72trueTb4b4b4, Te6edf3loraTb4b4b4.Te6edf3use_presetTb4b4b4, Ta5d6ff"Ta5d6ffuse_preset must be setTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ModemPresetTb4b4b4.Te6edf3LONG_FASTTb4b4b4, Te6edf3loraTb4b4b4.Te6edf3modem_presetTb4b4b4, Ta5d6ff"Ta5d6ffoffered preset appliedTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3RegionCodeTb4b4b4.Te6edf3USTb4b4b4, Te6edf3loraTb4b4b4.Te6edf3regionTb4b4b4, Ta5d6ff"Ta5d6ffoffered region appliedTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3loraTb4b4b4.Te6edf3channel_numTb4b4b4, Ta5d6ff"Ta5d6ffchannel_num reset to 0 for frequency derivationTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff0fTb4b4b4, Te6edf3loraTb4b4b4.Te6edf3override_frequencyTb4b4b4, Ta5d6ff"Ta5d6ffstale override_frequency dropped — firmware re-derives itTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3loraTb4b4b4.Te6edf3tx_powerTb4b4b4, Ta5d6ff"Ta5d6ffstale tx_power dropped — firmware picks the region maxTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff3Tb4b4b4, Te6edf3loraTb4b4b4.Te6edf3hop_limitTb4b4b4, Ta5d6ff"Ta5d6ffhop_limit falls back to the standard default, not the stale valueTa5d6ff"Tb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`SWITCH without an offered preset keeps the current preset and region and resets channel_num`Tb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// A channel-only beacon (no preset) must still reset channel_num=0 so firmware re-derives the frequency from
T8b949e// the new primary name, keep the current preset, and carry the current region (a zero region disables TX).
Tff7b72val Te6edf3current Tff7b72= Te6edf3radioLoraTb4b4b4.Te6edf3copyTb4b4b4(Te6edf3modem_preset Tff7b72= Te6edf3ModemPresetTb4b4b4.Te6edf3MEDIUM_FASTTb4b4b4, Te6edf3channel_num Tff7b72= T79c0ff5Tb4b4b4)
Tff7b72val Te6edf3beacon Tff7b72= Te6edf3MeshBeaconTb4b4b4(Te6edf3offer_channel Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffPartyNetTa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72val Te6edf3lora Tff7b72= Te6edf3beaconTb4b4b4.Te6edf3toJoinChannelSetTb4b4b4(Te6edf3BeaconJoinOptionTb4b4b4.Te6edf3SWITCHTb4b4b4, Te6edf3currentTb4b4b4)Tff7b72?.Te6edf3lora_config
Te6edf3assertNotNullTb4b4b4(Te6edf3loraTb4b4b4, Ta5d6ff"Ta5d6ffSWITCH must always carry lora so channel_num resetsTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3loraTb4b4b4.Te6edf3channel_numTb4b4b4, Ta5d6ff"Ta5d6ffchannel_num reset to 0 even without an offered presetTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3ModemPresetTb4b4b4.Te6edf3MEDIUM_FASTTb4b4b4, Te6edf3loraTb4b4b4.Te6edf3modem_presetTb4b4b4, Ta5d6ff"Ta5d6ffcurrent preset kept when none offeredTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3RegionCodeTb4b4b4.Te6edf3USTb4b4b4, Te6edf3loraTb4b4b4.Te6edf3regionTb4b4b4, Ta5d6ff"Ta5d6ffcurrent region carried when none offeredTa5d6ff"Tb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`join strips position sharing from the offered channel`Tb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// Privacy: joining a stranger's mesh must never broadcast our location (Apple sets positionPrecision=0).
Tff7b72val Te6edf3beacon Tff7b72=
Te6edf3MeshBeaconTb4b4b4(
Te6edf3offer_channel Tff7b72=
Te6edf3ChannelSettingsTb4b4b4(
Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffPartyNetTa5d6ff"Tb4b4b4,
Te6edf3module_settings Tff7b72= Te6edf3orgTb4b4b4.Te6edf3meshtasticTb4b4b4.Te6edf3protoTb4b4b4.Te6edf3ModuleSettingsTb4b4b4(Te6edf3position_precision Tff7b72= T79c0ff3T79c0ff2Tb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Te6edf3offer_preset Tff7b72= Te6edf3ModemPresetTb4b4b4.Te6edf3LONG_FASTTb4b4b4,
Te6edf3offer_region Tff7b72= Te6edf3RegionCodeTb4b4b4.Te6edf3USTb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3added Tff7b72= Te6edf3beaconTb4b4b4.Te6edf3toJoinChannelSetTb4b4b4(Te6edf3BeaconJoinOptionTb4b4b4.Te6edf3ADDTb4b4b4, Te6edf3radioLoraTb4b4b4)Tff7b72?.Te6edf3settingsTff7b72?.Te6edf3firstTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3switched Tff7b72= Te6edf3beaconTb4b4b4.Te6edf3toJoinChannelSetTb4b4b4(Te6edf3BeaconJoinOptionTb4b4b4.Te6edf3SWITCHTb4b4b4, Te6edf3radioLoraTb4b4b4)Tff7b72?.Te6edf3settingsTff7b72?.Te6edf3firstTb4b4b4(Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3addedTff7b72?.Te6edf3module_settingsTff7b72?.Te6edf3position_precisionTb4b4b4, Ta5d6ff"Ta5d6ffADD zeroes position precisionTa5d6ff"Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3switchedTff7b72?.Te6edf3module_settingsTff7b72?.Te6edf3position_precisionTb4b4b4, Ta5d6ff"Ta5d6ffSWITCH zeroes position precisionTa5d6ff"Tb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`encode then decode round-trips a beacon offer`Tb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3offer Tff7b72=
Te6edf3MeshBeaconOfferTb4b4b4(
Te6edf3fromNodeNum Tff7b72= T79c0ff4T79c0ff2Tb4b4b4,
Te6edf3beacon Tff7b72=
Te6edf3MeshBeaconTb4b4b4(
Te6edf3message Tff7b72= Ta5d6ff"Ta5d6ffJoin usTa5d6ff"Tb4b4b4,
Te6edf3offer_channel Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffPartyNetTa5d6ff"Tb4b4b4, Te6edf3psk Tff7b72= Ta5d6ff"Ta5d6ffsecretTa5d6ff"Tb4b4b4.Te6edf3encodeUtf8Tb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3offer_preset Tff7b72= Te6edf3ModemPresetTb4b4b4.Te6edf3LONG_FASTTb4b4b4,
Te6edf3offer_region Tff7b72= Te6edf3RegionCodeTb4b4b4.Te6edf3USTb4b4b4,
Tb4b4b4)Tb4b4b4,
Te6edf3snr Tff7b72= T79c0ff6.5fTb4b4b4,
Te6edf3rssi Tff7b72= Tff7b72-T79c0ff7T79c0ff0Tb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3restored Tff7b72= Te6edf3MeshBeaconOfferTb4b4b4.Te6edf3decodeTb4b4b4(Te6edf3offerTb4b4b4.Te6edf3encodeTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3offerTb4b4b4, Te6edf3restoredTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`encode then decode round-trips an absent rssi without collapsing it to zero`Tb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3offer Tff7b72=
Te6edf3MeshBeaconOfferTb4b4b4(
Te6edf3fromNodeNum Tff7b72= T79c0ff4T79c0ff2Tb4b4b4,
Te6edf3beacon Tff7b72= Te6edf3MeshBeaconTb4b4b4(Te6edf3message Tff7b72= Ta5d6ff"Ta5d6ffJoin usTa5d6ff"Tb4b4b4, Te6edf3offer_channel Tff7b72= Te6edf3ChannelSettingsTb4b4b4(Te6edf3name Tff7b72= Ta5d6ff"Ta5d6ffPartyNetTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3snr Tff7b72= T79c0ff6.5fTb4b4b4,
Te6edf3rssi Tff7b72= Tff7b72nullTb4b4b4,
Tb4b4b4)
Tff7b72val Te6edf3restored Tff7b72= Te6edf3MeshBeaconOfferTb4b4b4.Te6edf3decodeTb4b4b4(Te6edf3offerTb4b4b4.Te6edf3encodeTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3assertEqualsTb4b4b4(Te6edf3offerTb4b4b4, Te6edf3restoredTb4b4b4)
Te6edf3assertNullTb4b4b4(Te6edf3restoredTff7b72?.Te6edf3rssiTb4b4b4)
Tb4b4b4}

Tf0883e@Test
Tff7b72fun Td2a8ff`decode returns null for a malformed record`Tb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3assertNullTb4b4b4(Te6edf3MeshBeaconOfferTb4b4b4.Te6edf3decodeTb4b4b4(Ta5d6ff"Ta5d6ffnot-a-valid-recordTa5d6ff"Tb4b4b4)Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Served by rngit 1.5.0 - Generated in 0.08s